package com.ruihu.admin.module.system.login;

import com.ruihu.admin.common.anno.MethodLog;
import com.ruihu.admin.common.constant.JudgeEnum;
import com.ruihu.admin.common.domain.ResponseDTO;
import com.ruihu.admin.constant.CommonConst;
import com.ruihu.admin.constant.TerminalTypeEnum;
import com.ruihu.admin.module.system.department.dao.DepartmentDao;
import com.ruihu.admin.module.system.department.domain.entity.DepartmentEntity;
import com.ruihu.admin.module.system.privilege.service.PrivilegeUserService;
import com.ruihu.admin.module.system.user.dao.UserDao;
import com.ruihu.admin.module.system.user.constant.UserResponseCodeConst;
import com.ruihu.admin.module.system.user.constant.UserStatusEnum;
import com.ruihu.admin.module.system.user.domain.dto.UserDTO;
import com.ruihu.admin.module.system.user.domain.dto.UserLoginFormDTO;
import com.ruihu.admin.module.business.log.LogService;
import com.ruihu.admin.module.business.log.userloginlog.domain.UserLoginLogEntity;
import com.ruihu.admin.module.system.login.domain.KaptchaVO;
import com.ruihu.admin.module.system.login.domain.LoginDetailVO;
import com.ruihu.admin.module.system.login.domain.LoginPrivilegeDTO;
import com.ruihu.admin.module.system.login.domain.RequestTokenBO;
import com.ruihu.admin.module.system.privilege.domain.entity.PrivilegeEntity;
import com.ruihu.admin.util.BeanUtil;
import com.ruihu.admin.util.DigestUtil;
import com.ruihu.admin.util.IPUtil;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import eu.bitwalker.useragentutils.UserAgent;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * [  ]
 *
 * @author yandanyang
 * @version 1.0
 * @company Ruihu (Nanjing) Information Technology Co., Ltd
 * @copyright (c) 2018 Ruihu (Nanjing) Information Technology Co., LtdInc. All rights reserved.
 * @date 2019/3/27 0027 下午 18:10
 * @since JDK1.8
 */
@Slf4j
@Service
public class LoginService {

    private static final String VERIFICATION_CODE_REDIS_PREFIX = "vc_%s";

    @Autowired
    private UserDao userDao;

    @Autowired
    private DepartmentDao departmentDao;

    @Autowired
    private PrivilegeUserService privilegeUserService;

    @Autowired
    private LoginTokenService loginTokenService;

    @Autowired
    private LogService logService;

    @Autowired
    private DefaultKaptcha defaultKaptcha;

    @Autowired
    private ValueOperations<String, String> redisValueOperations;

    /**
     * 登陆
     *
     * @param loginForm 登录名 密码
     * @return 登录用户基本信息
     */
    @MethodLog
    public ResponseDTO<LoginDetailVO> login(@Valid UserLoginFormDTO loginForm, HttpServletRequest request) {
        /*if (TerminalTypeEnum.PC.equals(TerminalTypeEnum.of(loginForm.getGrantType()))) {
            // 增加删除已使用的验证码方式 频繁登录
            String redisVerificationCode = redisValueOperations.get(loginForm.getCodeUuid());
            redisValueOperations.getOperations().delete(loginForm.getCodeUuid());
            if (StringUtils.isEmpty(redisVerificationCode)) {
                return ResponseDTO.wrap(UserResponseCodeConst.VERIFICATION_CODE_INVALID);
            }
            if (!redisVerificationCode.equalsIgnoreCase(loginForm.getCode())) {
                return ResponseDTO.wrap(UserResponseCodeConst.VERIFICATION_CODE_NOT_MATCH);
            }
        }*/

        String loginPwd = DigestUtil.encryptPassword(CommonConst.Password.SALT_FORMAT, loginForm.getPassword());
        UserDTO userDTO = userDao.login(loginForm.getUsername(), loginPwd);
        if (null == userDTO) {
            return ResponseDTO.wrap(UserResponseCodeConst.LOGIN_FAILED);
        }
        if (UserStatusEnum.DISABLED.equalsValue(userDTO.getIsDisabled())) {
            return ResponseDTO.wrap(UserResponseCodeConst.IS_DISABLED);
        }
        //jwt token赋值
        String compactJws = loginTokenService.generateToken(userDTO);

        LoginDetailVO loginDTO = BeanUtil.copy(userDTO, LoginDetailVO.class);

        //获取前端功能权限
        loginDTO.setPrivilegeList(initUserPrivilege(userDTO.getId()));

        loginDTO.setXAccessToken(compactJws);
        DepartmentEntity departmentEntity = departmentDao.selectById(userDTO.getDepartmentId());
        loginDTO.setDepartmentName(departmentEntity.getDepartmentName());

        //判断是否为超管
        Boolean isSuperman = privilegeUserService.isSuperman(loginDTO.getId());
        loginDTO.setIsSuperMan(isSuperman);
        //登陆操作日志
        UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent"));
        UserLoginLogEntity logEntity =
                UserLoginLogEntity.builder()
                        .userId(userDTO.getId())
                        .username(userDTO.getUsername())
                        .remoteIp(IPUtil.getRemoteIp(request))
                        .remotePort(request.getRemotePort())
                        .remoteBrowser(userAgent.getBrowser().getName())
                        .remoteOs(userAgent.getOperatingSystem().getName())
                        .loginStatus(JudgeEnum.YES.getValue()).build();
        logService.addLog(logEntity);
        return ResponseDTO.succData(loginDTO);
    }

    /**
     * 手机端退出登陆，清除token缓存
     *
     * @param requestToken
     * @return 退出登陆是否成功，bool
     */
    public ResponseDTO<Boolean> logoutByToken(RequestTokenBO requestToken) {
        privilegeUserService.removeCache(requestToken.getRequestUserId());
        return ResponseDTO.succ();
    }

    /**
     * 获取验证码
     *
     * @return
     */
    public ResponseDTO<KaptchaVO> verificationCode() {
        KaptchaVO kaptchaVO = new KaptchaVO();
        String uuid = buildVerificationCodeRedisKey(UUID.randomUUID().toString());
        String kaptchaText = defaultKaptcha.createText();

        String base64Code = "";

        BufferedImage image = defaultKaptcha.createImage(kaptchaText);
        ByteArrayOutputStream outputStream = null;
        try {
            outputStream = new ByteArrayOutputStream();
            ImageIO.write(image, "jpg", outputStream);
            base64Code = Base64.encodeBase64String(outputStream.toByteArray());
        } catch (Exception e) {
            log.error("verificationCode exception .{}", e);
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (Exception e) {
                    log.error("verificationCode outputStream close exception .{}", e);
                }
            }
        }
        kaptchaVO.setUuid(uuid);
        kaptchaVO.setCode("data:image/png;base64," + base64Code);
        redisValueOperations.set(uuid, kaptchaText, 60L, TimeUnit.SECONDS);
        return ResponseDTO.succData(kaptchaVO);
    }

    private String buildVerificationCodeRedisKey(String uuid) {
        return String.format(VERIFICATION_CODE_REDIS_PREFIX, uuid);
    }

    /**
     * 初始化员工权限
     *
     * @param userId
     * @return
     */
    public List<LoginPrivilegeDTO> initUserPrivilege(Long userId) {
        List<PrivilegeEntity> privilegeList = privilegeUserService.getPrivilegesByuserId(userId);
        privilegeUserService.updateCachePrivilege(userId, privilegeList);
        return BeanUtil.copyList(privilegeList, LoginPrivilegeDTO.class);
    }

    public LoginDetailVO getSession(RequestTokenBO requestUser) {
        LoginDetailVO loginDTO = BeanUtil.copy(requestUser.getUserBO(), LoginDetailVO.class);
        List<PrivilegeEntity> privilegeEntityList = privilegeUserService.getPrivilegesByuserId(requestUser.getRequestUserId());
        //======  开启缓存   ======
        if (privilegeEntityList == null) {
            List<LoginPrivilegeDTO> loginPrivilegeDTOS = initUserPrivilege(requestUser.getRequestUserId());
            loginDTO.setPrivilegeList(loginPrivilegeDTOS);
        } else {
            loginDTO.setPrivilegeList(BeanUtil.copyList(privilegeEntityList, LoginPrivilegeDTO.class));
        }

        //======  不开启缓存   ======
//        List<LoginPrivilegeDTO> loginPrivilegeDTOS = initUserPrivilege(requestUser.getRequestUserId());
//        loginDTO.setPrivilegeList(loginPrivilegeDTOS);

        //判断是否为超管
        Boolean isSuperman = privilegeUserService.isSuperman(loginDTO.getId());
        loginDTO.setIsSuperMan(isSuperman);
        return loginDTO;
    }
}
